﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace Rung.Soft.Jx3Tookit.Addon.AutoPress.Utility
{
    internal class Win32API
    {
        internal const int WM_KEYDOWN = 0x100;
        internal const int WM_SETTEXT = 0x000C;
        internal const int WM_LBUTTONDOWN = 0x0201;
        internal const int WM_LBUTTONUP = 0x0202;
        internal const int WM_CLOSE = 0x0010;
        internal const int WH_KEYBOARD_LL = 13; //全局键盘钩子

        /// <summary>
        /// 用于查找操作系统中打开的窗口中，指定窗口类型、或者指定窗体名称的窗口。
        /// 这两个参数知道一个即可，另一个可以填null。
        /// </summary>
        /// <param name="lpClassName">窗体的类名 例如对话框类是"#32770"</param>
        /// <param name="lpWindowName">窗体的标题 例如打开记事本 标题是"无标题 - 记事本"</param>
        [DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
        internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        /// <summary>
        /// 用于获得窗口中子窗口的句柄，子窗口指的其实就是窗口中的各种控件。
        /// </summary>
        /// <param name="parent">父窗体的句柄 如果为null，则函数以桌面窗口为父窗口，查找桌面窗口的所有子窗口</param>
        /// <param name="childe">子窗体的句柄 指示获得的是同一类型中的第几个子窗口，填IntPtr.Zero则表示获得第一个子窗口。</param>
        /// <param name="strclass">子窗体的类名 为""表示所有类</param>
        /// <param name="FrmText">子窗体的标题 为""表示要查找的窗体无标题 如空白的textBox控件</param>
        /// <returns></returns>
        [DllImport("User32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Auto)]
        internal static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childe, string strclass, string FrmText);

        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        internal static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);

        /// <summary>
        /// 触发一个按键事件，也就是说回产生一个WM_KEYDOWN或WM_KEYUP消息。
        /// </summary>
        /// <param name="bVk"> virtual-key code</param>
        /// <param name="bScan">hardware scan code</param>
        /// <param name="dwFlags"> flags specifying various function options。0 为按下，2为释放</param>
        /// <param name="dwExtraInfo">additional data associated with keystroke。一般情况下设成为 0</param>
        [DllImport("user32.dll")]
        internal static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

        [DllImport("user32.dll", EntryPoint = "GetForegroundWindow")]
        internal static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        internal static extern bool ReleaseCapture();

        #region 钩子
        internal delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        /// <summary>
        /// 安装钩子
        /// </summary>
        /// <param name="idHook">钩子类型</param>
        /// <param name="lpfn">函数指针</param>
        /// <param name="hMod">包含钩子函数的模块(EXE、DLL)句柄; 一般是 HInstance; 如果是当前线程这里可以是 0</param>
        /// <param name="dwThreadId">关联的线程; 可用 GetCurrentThreadId 获取当前线程; 0 表示是系统级钩子</param>
        /// <returns>返回钩子的句柄; 0 表示失败</returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        //钩子类型 idHook 选项:
        //WH_MSGFILTER       = -1; {线程级; 截获用户与控件交互的消息}
        //WH_JOURNALRECORD   = 0;  {系统级; 记录所有消息队列从消息队列送出的输入消息, 在消息从队列中清除时发生; 可用于宏记录}
        //WH_JOURNALPLAYBACK = 1;  {系统级; 回放由 WH_JOURNALRECORD 记录的消息, 也就是将这些消息重新送入消息队列}
        //WH_KEYBOARD        = 2;  {系统级或线程级; 截获键盘消息}
        //WH_GETMESSAGE      = 3;  {系统级或线程级; 截获从消息队列送出的消息}
        //WH_CALLWNDPROC     = 4;  {系统级或线程级; 截获发送到目标窗口的消息, 在 SendMessage 调用时发生}
        //WH_CBT             = 5;  {系统级或线程级; 截获系统基本消息, 譬如: 窗口的创建、激活、关闭、最大最小化、移动等等}
        //WH_SYSMSGFILTER    = 6;  {系统级; 截获系统范围内用户与控件交互的消息}
        //WH_MOUSE           = 7;  {系统级或线程级; 截获鼠标消息}
        //WH_HARDWARE        = 8;  {系统级或线程级; 截获非标准硬件(非鼠标、键盘)的消息}
        //WH_DEBUG           = 9;  {系统级或线程级; 在其他钩子调用前调用, 用于调试钩子}
        //WH_SHELL           = 10; {系统级或线程级; 截获发向外壳应用程序的消息}
        //WH_FOREGROUNDIDLE  = 11; {系统级或线程级; 在程序前台线程空闲时调用}
        //WH_CALLWNDPROCRET  = 12; {系统级或线程级; 截获目标窗口处理完毕的消息, 在 SendMessage 调用后发生}

        /// <summary>
        /// 卸载钩子
        /// </summary>
        /// <param name="hhk">钩子的句柄</param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern IntPtr GetModuleHandle(string lpModuleName);

        #endregion
    }
}
